/**
 * 地理计算工具类
 * 提供距离计算、坐标转换等功能
 */

const EARTH_RADIUS = 6371000; // 地球半径（米）

/**
 * 使用Haversine公式计算两点间的距离
 * @param {Number} lat1 - 第一个点的纬度
 * @param {Number} lng1 - 第一个点的经度
 * @param {Number} lat2 - 第二个点的纬度
 * @param {Number} lng2 - 第二个点的经度
 * @returns {Number} 距离（米）
 */
function calculateDistance(lat1, lng1, lat2, lng2) {
  const toRad = angle => (angle * Math.PI) / 180;
  
  const dLat = toRad(lat2 - lat1);
  const dLng = toRad(lng2 - lng1);
  
  const a = 
    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) *
    Math.sin(dLng / 2) * Math.sin(dLng / 2);
  
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  const distance = EARTH_RADIUS * c;
  
  return distance;
}

/**
 * 判断用户是否在地理围栏内
 * @param {Object} userPos - 用户位置 {latitude, longitude}
 * @param {Object} targetPos - 目标位置 {latitude, longitude}
 * @param {Number} radius - 围栏半径（米）
 * @returns {Boolean} 是否在围栏内
 */
function isInGeofence(userPos, targetPos, radius) {
  const distance = calculateDistance(
    userPos.latitude,
    userPos.longitude,
    targetPos.latitude,
    targetPos.longitude
  );
  return distance <= radius;
}

/**
 * GCJ02坐标转WGS84坐标（火星坐标系转GPS坐标系）
 * @param {Number} lat - GCJ02纬度
 * @param {Number} lng - GCJ02经度
 * @returns {Object} {latitude, longitude} WGS84坐标
 */
function gcj02ToWgs84(lat, lng) {
  // 简化算法（精度足够日常使用）
  const PI = 3.14159265358979324;
  const a = 6378245.0; // 长半轴
  const ee = 0.00669342162296594323; // 偏心率平方
  
  let dLat = transformLat(lng - 105.0, lat - 35.0);
  let dLng = transformLng(lng - 105.0, lat - 35.0);
  const radLat = lat / 180.0 * PI;
  let magic = Math.sin(radLat);
  magic = 1 - ee * magic * magic;
  const sqrtMagic = Math.sqrt(magic);
  dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
  dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
  
  return {
    latitude: lat - dLat,
    longitude: lng - dLng
  };
}

/**
 * WGS84坐标转GCJ02坐标（GPS坐标系转火星坐标系）
 * @param {Number} lat - WGS84纬度
 * @param {Number} lng - WGS84经度
 * @returns {Object} {latitude, longitude} GCJ02坐标
 */
function wgs84ToGcj02(lat, lng) {
  const PI = 3.14159265358979324;
  const a = 6378245.0;
  const ee = 0.00669342162296594323;
  
  let dLat = transformLat(lng - 105.0, lat - 35.0);
  let dLng = transformLng(lng - 105.0, lat - 35.0);
  const radLat = lat / 180.0 * PI;
  let magic = Math.sin(radLat);
  magic = 1 - ee * magic * magic;
  const sqrtMagic = Math.sqrt(magic);
  dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
  dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
  
  return {
    latitude: lat + dLat,
    longitude: lng + dLng
  };
}

// 辅助函数
function transformLat(x, y) {
  let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
  ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
  ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0;
  ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0;
  return ret;
}

function transformLng(x, y) {
  let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
  ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
  ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0;
  ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x / 30.0 * Math.PI)) * 2.0 / 3.0;
  return ret;
}

module.exports = {
  calculateDistance,
  isInGeofence,
  gcj02ToWgs84,
  wgs84ToGcj02
};

